/*--------------------------------------------------------------------------------------*\
**
** adv_ferry.cpp
**
** Heroes IV
** Copyright 2000, The 3DO Company
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "adventure_object_memory_cache.h"

#include "adventure_events_base.h"
#include "adventure_map.h"
#include "adventure_object.h"
#include "compressed_filter.h"

namespace 
{
	const int k_memory_event_buffer_size = 200;
};

//////////////////////////////////////////////////////////////////////////////////////////

t_adventure_object_memory_cache::t_adventure_object_memory_cache()
{
	m_data_buffer			= NULL;
	m_is_town				= false;
	m_memory_cache_refrence	= 0;
}

t_adventure_object_memory_cache::~t_adventure_object_memory_cache()
{
	m_data_buffer			= NULL;
}
	
t_memory_buffer_counted_ptr const & t_adventure_object_memory_cache::get_data_buffer()
{
	return m_data_buffer;
}

bool	t_adventure_object_memory_cache::update_state( t_adventure_object * object )
{
	assert(object!=NULL);

	m_data_buffer   = NULL;

	m_data_buffer	= t_adventure_event_functions::create_state_cahce_buffer( object );

	return true;
}

int		t_adventure_object_memory_cache::increment()
{
	return (++m_memory_cache_refrence);
}

int		t_adventure_object_memory_cache::decrement()
{
	return (--m_memory_cache_refrence);
}

bool t_adventure_object_memory_cache::read( std::streambuf & buffer )
{ 
	int event_buffer_flag  = 	get<t_uint32> ( buffer );
	
	if (event_buffer_flag != 0)
	{
		if (m_data_buffer == NULL)
			m_data_buffer = new t_memory_buffer_counted ( k_memory_event_buffer_size );

		m_data_buffer->read( buffer );
	}
	
	m_is_town	= get<bool>(buffer);
	
	return true;
}

bool t_adventure_object_memory_cache::write( std::streambuf & buffer ) 
{ 
	if (m_data_buffer.get() != 0)
	{
		put<t_uint32> (buffer, 1);
		
		m_data_buffer->write( buffer );
	}
	else
		put<t_uint32> (buffer, 0);

	put<bool>(buffer,m_is_town);

	return true;
}

//////////////////////////////////////////////////////////////////////////////////////////

t_adventure_object_memory_cache_refrence::t_adventure_object_memory_cache_refrence()
{
	m_cache			= NULL;
	m_manager		= NULL;
	m_object_gid	= k_invalid_global_id;
}

t_adventure_object_memory_cache_refrence::~t_adventure_object_memory_cache_refrence()
{
	if (m_cache != NULL && m_manager != NULL)
	{
		if (m_cache->decrement() <= 0)
			m_manager->remove( m_object_gid );
	}

	m_cache			= NULL;
	m_manager		= NULL;
	m_object_gid	= k_invalid_global_id;
}

void	t_adventure_object_memory_cache_refrence::set_adventure_manager_for_memory_cache( t_adventure_map * map )
{
	assert(map!=NULL);

	m_manager = map->get_cache_manager();
}

void	t_adventure_object_memory_cache_refrence::set_cache_for_memory_cache( t_adventure_object_memory_cache * cache )
{
	if (m_cache!=NULL)
		m_cache->decrement();

	m_cache = cache;

	if (m_cache!=NULL)
		m_cache->increment();
}	

void	t_adventure_object_memory_cache_refrence::set_global_id_for_memory_cache( t_adventure_global_id	object_gid )
{
	m_object_gid = object_gid;
}

//////////////////////////////////////////////////////////////////////////////////////////
//the adventure_object_cache manager 

t_adventure_object_cache_manager::t_adventure_object_cache_manager()
{

}

t_adventure_object_cache_manager::~t_adventure_object_cache_manager()
{
	int size = m_replay_event_state_map.size();
}

bool	t_adventure_object_cache_manager::attach_adv_objects_to_their_cache( t_adventure_map* map )
{
	assert(map!=NULL);

	t_adventure_state_event_cache_map::const_iterator adv_state_cache_iter;
	
	for (adv_state_cache_iter = m_replay_event_state_map.begin(); adv_state_cache_iter != m_replay_event_state_map.end(); adv_state_cache_iter++)
	{
		t_adventure_object* adv_obj = map->get_adventure_object_with_gid( adv_state_cache_iter->first );
		
		if (adv_obj == NULL) 
			continue;
	
		adv_obj->set_global_id_for_memory_cache( adv_obj->get_global_id() );
		adv_obj->set_cache_for_memory_cache( adv_state_cache_iter->second );
		adv_obj->set_adventure_manager_for_memory_cache( map );
	}

	return true;
}

bool	t_adventure_object_cache_manager::is_empty( t_adventure_global_id const & global_id )
{
	if (m_replay_event_state_map.find(global_id) == m_replay_event_state_map.end())
		return true;

	return false;
}

// -------------------------------------------------------------------
// insert : adds the object into the map ( as an in memory save buffer )
// -------------------------------------------------------------------
void	t_adventure_object_cache_manager::insert( t_adventure_object * object )
{
	////////////////////////////////////////////////////////////////////////
	//set the adventure cache memory buffer for this object. 
	// if it already is in the map, just attach the object to its existing 
	// cache.

	t_adventure_global_id						object_gid = object->get_global_id();
	
	if (is_empty( object_gid ) == true)
	{
		t_adventure_object_memory_cache_ptr			state_cache_buffer(new t_adventure_object_memory_cache);
		m_replay_event_state_map[object_gid] =		state_cache_buffer;
		
		object->set_global_id_for_memory_cache( object_gid );
		object->set_cache_for_memory_cache( state_cache_buffer );
		object->set_adventure_manager_for_memory_cache( object->get_map() );

		state_cache_buffer->update_state(object);
	}
	else
	{
		t_adventure_object_memory_cache_ptr			state_cache_buffer = m_replay_event_state_map[object_gid];
		
		object->set_global_id_for_memory_cache( object_gid );
		object->set_cache_for_memory_cache( state_cache_buffer );
		object->set_adventure_manager_for_memory_cache( object->get_map() );
	}
}

// -------------------------------------------------------------------
// remove : removes the objects cache from the map 
// -------------------------------------------------------------------
void	t_adventure_object_cache_manager::remove( t_adventure_object * object )
{
	t_adventure_global_id object_gid = object->get_global_id();
	
	remove(object_gid);
}

// -------------------------------------------------------------------
// remove : removes the objects cache from the map 
// -------------------------------------------------------------------
void	t_adventure_object_cache_manager::remove( t_adventure_global_id object_gid )
{
	if (is_empty( object_gid ) == true)
		return;

	m_replay_event_state_map[object_gid] = NULL;
	m_replay_event_state_map.erase(object_gid);
}

// -------------------------------------------------------------------
// update : updates the objects in memory save buffer if it is in the map
// -------------------------------------------------------------------
void	t_adventure_object_cache_manager::update( t_adventure_object * object )
{
	t_adventure_global_id object_gid = object->get_global_id();

	if (is_empty( object_gid ) == true)
		return;
	
	m_replay_event_state_map[object_gid]->update_state(object);
}

// -------------------------------------------------------------------
// get_memory_cache : gets the objects in memory save buffer
// -------------------------------------------------------------------
t_adventure_object_memory_cache *	t_adventure_object_cache_manager::get_memory_cache( t_adventure_object * object )
{
	t_adventure_global_id object_gid = object->get_global_id();

	if (is_empty( object_gid ) == true)
		return NULL;
	
	return m_replay_event_state_map[object_gid];
}

// -------------------------------------------------------------------
// read : reads the saved map
// -------------------------------------------------------------------
bool	t_adventure_object_cache_manager::read( std::streambuf & buffer )
{
	m_replay_event_state_map.clear();

	int map_size = get<t_uint32>( buffer );
	
	for (int i = 0; i < map_size; i++)
	{	
		t_adventure_object_memory_cache_ptr			state_cache_buffer(new t_adventure_object_memory_cache);
		t_adventure_global_id						global_id = k_invalid_global_id;
		
		global_id = read_adventure_global_id( buffer );
		
		if (state_cache_buffer->read( buffer ) == false)
			return false;
		
		m_replay_event_state_map[global_id] = state_cache_buffer;
	}
	
	return true;
}

// -------------------------------------------------------------------
// write : write the map
// -------------------------------------------------------------------
bool	t_adventure_object_cache_manager::write( std::streambuf & buffer )
{
	int map_size = m_replay_event_state_map.size();
	
	put<t_uint32>(buffer, map_size);
	
	t_adventure_state_event_cache_map::const_iterator adv_state_cache_iter;
	
	for (adv_state_cache_iter = m_replay_event_state_map.begin(); adv_state_cache_iter != m_replay_event_state_map.end(); adv_state_cache_iter++)
	{
		write_adventure_global_id( buffer, adv_state_cache_iter->first );
		
		if (adv_state_cache_iter->second->write( buffer ) == false)
			return false;
	}
	
	return true;
}
